﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Profile;
using System.Web.Mvc;
using System.Web.Security;

namespace ECSE6770.Models
{

    public class ChangePasswordModel
    {
        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Current password")]
        public string OldPassword { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 5)]
        [DataType(DataType.Password)]
        [Display(Name = "New password")]
        public string NewPassword { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm new password")]
        [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    }

    public class LogOnModel
    {
        [Required]
        [Display(Name = "User name")]
        public string UserName { get; set; }

        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [Display(Name = "Remember me?")]
        public bool RememberMe { get; set; }
    }

    public class RegisterModel
    {
        [Required]
        [Display(Name = "User name")]
        public string UserName { get; set; }

        [Required]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "Email address")]
        public string Email { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 5)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    }

    public class AdminNewUserModel
    {
        [Required]
        [Display(Name = "User name")]
        public string UserName { get; set; }

        [Required]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "Email address")]
        public string Email { get; set; }
    }

    public class UserProfile
    {
        public UserProfile() { }

        public UserProfile(string userName)
        {
            Init(userName);
        }

        public UserProfile(MembershipUser user)
        {
            _user = user;
            Init(_user.UserName);
        }

        public UserProfile(UserInterop i)
        {
            _interop = i;
            Init(i.UserName);
        }

        protected void Init(string userName)
        {
            _profile = new ProfileBase();
            _profile.Initialize(userName, true);
            if (_user == null)
                _user = Membership.GetUser(userName);
        }

        protected ProfileBase _profile;
        protected MembershipUser _user;
        protected string[] _roles;
        protected bool? _isAdmin;
        protected UserInterop _interop;

        private string ProfileProperty(string key)
        {
            var value = _profile.GetPropertyValue(key);
            return value != null ? value.ToString() : null;
        }

        public UserInterop Interop
        {
            get
            {
                if (_interop == null)
                    _interop = ContextManager.LoadUserInterop(_user.UserName);
                return _interop;
            }
        }

        public string UserName
        {
            get { return _user.UserName; }
        }

        public string[] Roles
        {
            get
            {
                if (_roles == null)
                    _roles = System.Web.Security.Roles.GetRolesForUser(UserName);
                return _roles;
            }
        }

        public bool IsAdmin
        {
            get
            {
                if (_isAdmin == null)
                    _isAdmin = Roles.Contains("Admin");
                return _isAdmin.Value;
            }
        }

        public bool IsSuperAdmin
        {
            get { return UserName == System.Configuration.ConfigurationManager.AppSettings["SuperAdminName"]; }
        }

        [Required]
        [Display(Name = "First Name")]
        public string FirstName
        {
            get { return ProfileProperty("FirstName"); }
            set { _profile.SetPropertyValue("FirstName", value); }
        }

        [Required]
        [Display(Name = "Last Name")]
        public string LastName
        {
            get { return ProfileProperty("LastName"); }
            set { _profile.SetPropertyValue("LastName", value); }
        }

        [Display(Name = "Title (Mr./Mrs./etc)")]
        public string Title
        {
            get { return ProfileProperty("Title"); }
            set { _profile.SetPropertyValue("Title", value); }
        }

        [Required]
        [Display(Name = "Email Address")]
        [DataType(DataType.EmailAddress)]
        public string EmailAddress
        {
            get { return _user.Email; }
            set { _user.Email = value; }
        }

        [Required]
        [Display(Name = "Phone Number")]
        [DataType(DataType.PhoneNumber)]
        public string PhoneNumber
        {
            get { return ProfileProperty("PhoneNumber"); }
            set { _profile.SetPropertyValue("PhoneNumber", value); }
        }

        [Display(Name = "Fax")]
        [DataType(DataType.PhoneNumber)]
        public string Fax
        {
            get { return ProfileProperty("Fax"); }
            set { _profile.SetPropertyValue("Fax", value); }
        }

        [Required]
        [Display(Name = "Job Title")]
        public string JobTitle
        {
            get { return ProfileProperty("JobTitle"); }
            set { _profile.SetPropertyValue("JobTitle", value); }
        }

        [Required]
        [Display(Name = "Organization Name")]
        public string OrganizationName
        {
            get { return ProfileProperty("OrganizationName"); }
            set { _profile.SetPropertyValue("OrganizationName", value); }
        }

        [Required]
        [Display(Name = "Organization Country")]
        public string OrganizationCountry
        {
            get { return ProfileProperty("OrganizationCountry"); }
            set { _profile.SetPropertyValue("OrganizationCountry", value); }
        }

        [Required]
        [Display(Name = "Organization Address")]
        [DataType(DataType.MultilineText)]
        public string OrganizationAddress
        {
            get { return ProfileProperty("OrganizationAddress"); }
            set { _profile.SetPropertyValue("OrganizationAddress", value); }
        }

        [Required]
        [Display(Name = "City")]
        public string OrganizationCity
        {
            get { return ProfileProperty("OrganizationCity"); }
            set { _profile.SetPropertyValue("OrganizationCity", value); }
        }

        [Required]
        [Display(Name = "State")]
        public string OrganizationState
        {
            get { return ProfileProperty("OrganizationState"); }
            set { _profile.SetPropertyValue("OrganizationState", value); }
        }

        [Required]
        [Display(Name = "Zip Code")]
        public string OrganizationZip
        {
            get { return ProfileProperty("OrganizationZip"); }
            set { _profile.SetPropertyValue("OrganizationZip", value); }
        }

        /// <summary>
        /// Returns a name of the following format:
        /// Title [if any] First Last
        /// </summary>
        /// <returns></returns>
        public string NameFormatted()
        {
            string name = String.Concat(FirstName, " ", LastName);
            return String.IsNullOrWhiteSpace(Title) ? name : String.Concat(Title, " ", name);
        }

        /// <summary>
        /// Returns whether or not this profile has been filled out entirely.
        /// </summary>
        /// <returns></returns>
        public bool HasAllRequiredFields()
        {
            var props = from p in this.GetType().GetProperties()
                        let attr = p.GetCustomAttributes(typeof(RequiredAttribute), true)
                        where attr.Length == 1
                        select p;

            foreach (var prop in props)
            {
                if (String.IsNullOrWhiteSpace((string)prop.GetValue(this, null)))
                    return false;
            }
            return true;
        }
    }

    public class EditProfileModel : UserProfile
    {
        public EditProfileModel()
        {
            /* Caution...dirty hack */
            string bindAs = HttpContext.Current.Request.Form["BindModelAs"];
            if (!String.IsNullOrEmpty(bindAs))
                Init(bindAs);
            else
            {

                _profile = System.Web.HttpContext.Current.Profile;
                _user = Membership.GetUser(HttpContext.Current.User.Identity.Name);
            }
        }

        public EditProfileModel(string userName)
        {
            Init(userName);
        }

        public void Save()
        {
            _profile.Save();
            Membership.UpdateUser(_user);
        }

        public void UpdateRoles()
        {
            List<string> toAdd = new List<string>();
            List<string> toRemove = new List<string>();

            HashSet<string> current = new HashSet<string>(Roles);
            HashSet<string> desired = new HashSet<string>(EditedRoles ?? new string[0]);

            foreach (string s in current)
                if (!desired.Contains(s))
                    toRemove.Add(s);

            foreach (string s in desired)
                if (!current.Contains(s))
                    toAdd.Add(s);

            if (toAdd.Count > 0)
                System.Web.Security.Roles.AddUserToRoles(UserName, toAdd.ToArray());
            if (toRemove.Count > 0)
                System.Web.Security.Roles.RemoveUserFromRoles(UserName, toRemove.ToArray());
        }

        /// <summary>
        /// Used for POSTed values
        /// </summary>
        public string[] EditedRoles { get; set; }
    }
}
